<template>
  <rt-view>
    <rt-header>
      <rt-list-header>
        <!-- <rt-header-icon slot="icon" icon="rt-portal-default" /> -->
        <rt-list-dropdown
          v-if="hideTitle"
          :menu-list="titleList.value"
          :value="selected"
          icon="rt-portal-default"
          @input="titleSelect"
        />
        <rt-header-icon
          v-if="!hideTitle"
          slot="icon"
          icon="rt-portal-default"
        />
        <rt-header-title v-if="!hideTitle" :title="viewTitle" />
        <template slot="btn">
          <rt-header-button-group>
            <rt-button
              v-for="(item, index) in buttonsOfButtonGroup"
              :key="index"
              :icon-name="item.iconName"
              :type="
                item.operate == 'new' || (item.type && item.type === 'primary')
                  ? 'primary'
                  : 'default'
              "
              @click="handleClick(item.operate)"
              >{{ item.operateName }}
            </rt-button>
          </rt-header-button-group>

          <rt-button
            v-for="(item, index) in buttonsMore"
            :key="index"
            :type="
              item.operate == 'new' || (item.type && item.type === 'primary')
                ? 'primary'
                : 'default'
            "
            :icon-name="item.iconName"
            @click="handleClick(item.operate)"
            >{{ item.operateName }}
          </rt-button>
        </template>

        <rt-search
          v-if="operations.includes('search')"
          slot="search"
          v-model="quickSearchValue"
          :placeholder="searchPlaceholder"
          :more="operations.includes('advanced-search')"
          @on-search="refreshTable()"
        />
      </rt-list-header>
      <rt-list-filter
        v-if="operations.includes('advanced-search')"
        slot="extra"
      >
        <!-- <rt-content> -->
        <slot name="search" />
        <!-- </rt-content> -->
        <div v-if="lineBreak"><br /><br /><br /></div>
        <template slot="btns">
          <rt-button @click="resetTableParam()">重置</rt-button>
          <rt-button type="primary" @click="refreshTable()">搜索</rt-button>
        </template>
      </rt-list-filter>
      <!-- 导出对话框 -->
      <el-dialog
        v-if="operations.includes('export') && isShowExportDialog"
        :visible.sync="exportForm.visible"
        class="rt-dialog"
        title="请输入导出文件名"
        width="30%"
      >
        <el-container class="rt-edit">
          <!-- <el-header class="rt-edit__header-dialog">
              <span class="title header__title">请输入导出文件名</span>
              <el-row>
                <el-button class="el-dialog__headerbtn" @click="exportForm.visible = false">
                  <rt-icon name="rt-base-export"></rt-icon>
                </el-button>
              </el-row>
            </el-header> -->
          <el-main class="rt-edit__body">
            <el-form :model="exportForm" label-width="0" @submit.native.prevent>
              <rt-row :gutter="15">
                <rt-col>
                  <el-form-item>
                    <rt-input
                      v-model="exportForm.fileName"
                      :placeholder="'默认：' + exportFileName"
                      autocomplete="off"
                    />
                  </el-form-item>
                </rt-col>
              </rt-row>
            </el-form>
          </el-main>
        </el-container>
        <span slot="footer" class="dialog-footer">
          <el-button @click="exportForm.visible = false">取 消</el-button>
          <el-button type="primary" @click="exportViewData">确 定</el-button>
        </span>
      </el-dialog>
    </rt-header>
    <rt-content>
      <rt-table
        ref="multipleTable"
        :fetch="tableFetch"
        :total-record="tableTotals"
        :sectionable="false"
        tooltip-effect="dark"
        @selection-change="handleSelectionChange"
        @sort-change="handleSortChange"
        @header-click="handleHeaderClick"
      >
        <!-- 序号 -->
        <rt-table-column
          v-if="isMultiple"
          :selectable="selectable"
          type="selection"
          width="55"
        />
        <rt-table-column
          v-for="(column, index) in columns"
          :fixed="column.autoCol === true || column.autoCol === undefined"
          :label="column.label"
          :prop="column.prop"
          :width="
            column.priority_width
              ? column.priority_width
              : column.width
              ? column.width
              : ''
          "
          :min-width="
            `${
              column.sortable
                ? column.label.length * 30 > 100
                  ? column.label.length * 30
                  : columnWidthNarrow
                : column.width
                ? column.width
                : columnWidthNarrow
            }`
          "
          :sortable="column.sortable ? 'custom' : false"
          :align="column.type === 'number' ? 'right' : 'left'"
          :header-align="column.type === 'number' ? 'right' : 'left'"
          :key="index"
        >
          <template slot-scope="scope">
            <el-link
              v-if="column.type === 'url'"
              :underline="false"
              type="primary"
              @click="handleRowLinkClick(scope.row)"
              >{{ column.map ? column.map(scope.row) : scope.row[column.prop] }}
            </el-link>
            <template v-else-if="column.type === 'date'"
              >{{ scope.row[column.prop] | moment('YYYY-MM-DD') }}
            </template>
            <template v-else-if="column.type === 'datetime'"
              >{{ scope.row[column.prop] | moment('YYYY-MM-DD HH:mm') }}
            </template>
            <template v-else-if="column.format"
              >{{ scope.row[column.prop] | moment(column.format) }}
            </template>
            <template v-else-if="column.type === 'imagesrc'">
              <img
                v-if="
                  scope.row[column.prop] != undefined &&
                    !scope.row[column.prop] != null
                "
                :src="scope.row[column.prop]"
                :class="column.classname"
              />
            </template>
            <template v-else-if="column.type === 'imagebyte'">
              <img
                v-if="
                  scope.row[column.prop] != undefined &&
                    !scope.row[column.prop] != null
                "
                :src="'data:image/png;base64,' + scope.row[column.prop]"
                :class="column.classname"
              />
            </template>
            <template v-else-if="column.type === 'customizeAction'">
              <el-link
                :underline="false"
                type="primary"
                @click="customAction(scope.row, column.actionId)"
                >{{
                  column.map ? column.map(scope.row) : scope.row[column.prop]
                }}
              </el-link>
            </template>
            <template v-else
              >{{ column.map ? column.map(scope.row) : scope.row[column.prop] }}
            </template>
          </template>
        </rt-table-column>
      </rt-table>
    </rt-content>
  </rt-view>
</template>

<script>
import util from '../../libs/util';
import exp from '../../mixins/export';

export default {
  mixins: [exp],
  props: {
    columns: {
      type: [Array, Object],
      required: true
    },
    searchPlaceholder: {
      type: String,
      default: '请输入关键字进行搜索'
    },
    // eslint-disable-next-line vue/require-default-prop
    title: {
      type: String
    },
    // 重置，查询按钮是否换行
    lineBreak: {
      type: Boolean,
      default: false
    },
    // 隐藏左上角标题
    hideTitle: {
      type: Boolean,
      default: false
    },
    operations: {
      type: Array,
      default: () => []
    },
    // 自定义按钮
    customOperations: {
      type: Array,
      default: () => []
    },
    // 按钮自定义操作
    customButtonOperation: {
      type: Object,
      default: () => ({})
    },
    // eslint-disable-next-line vue/require-default-prop
    customLoadDataApi: {
      type: [String, Object]
    },
    // 自定义列表操作
    // eslint-disable-next-line vue/require-default-prop
    customizeAction: {
      type: Function
    },
    isMultiple: {
      type: Boolean,
      default: true
    },
    controllerName: {
      type: String,
      required: true
    },
    inputSearchParam: {
      type: Array,
      default: () => []
    },
    searchParam: {
      type: Array,
      default: () => []
    },
    //指定默认的查询条件
    defaultParam: {
      type: Array,
      default: () => []
    },
    //表名
    tableName: {
      type: String,
      required: true
    },
    linkPageType: {
      type: String,
      default: 'edit' /* 连接页面类型：readonly | edit */
    },
    // 根据每行记录处理连接页面类型
    // eslint-disable-next-line vue/require-default-prop
    handleLinkPageType: {
      type: Function
    },
    linkPageMode: {
      type: String,
      default:
        'replace' /* 连接页面的打开方式: replace | dialog，如果是 dialog，则必须提供 linkPage 参数 */
    },
    relatedAttr: {
      type: Object,
      default: () => ({})
    },
    // 自定义传参
    // eslint-disable-next-line vue/require-default-prop
    // eslint-disable-next-line vue/require-default-prop
    setParams: {
      type: Function
    },
    // 高级查询重置
    // eslint-disable-next-line vue/require-default-prop
    reset: {
      type: Function
    },
    titleList: {
      type: Object,
      default: () => ({})
    },
    //是否显示导出弹窗
    isShowExportDialog: {
      type: Boolean,
      default: false
    },
    //自定义哪些行数据不需要勾选
    disableMulti: {
      type: Object,
      default: () => ({})
    }
  },
  data() {
    return {
      tableTotals: 0,
      normalOperations: [
        {
          operate: 'new',
          operateName: '新建',
          iconName: 'rt-portal-add',
          type: 'primary'
        },
        { operate: 'delete', operateName: '删除', iconName: 'rt-base-delete' },
        { operate: 'import', operateName: '导入', iconName: 'rt-base-import' },
        {
          operate: 'export',
          operateName: '导出',
          iconName: 'rt-portal-export'
        },
        {
          operate: 'activate',
          operateName: '激活',
          iconName: 'rt-portal-able'
        },
        {
          operate: 'deactivate',
          operateName: '停用',
          iconName: 'rt-base-disable'
        }
      ].concat(this.customOperations),
      privilege: {},
      // 列宽度
      columnWidthWide: '520',
      columnWidthMedium: '320',
      columnWidthNarrow: '120',
      quickSearchValue: '',
      selectedDatas: [],
      orderByList: [],
      lastClickedColumn: '',
      searchList: this.searchParam,
      isPrimary: false
    };
  },
  computed: {
    viewTitle() {
      return this.title;
    },
    operationsButtons() {
      let customOperationCodes = [];
      if (this.customOperations && this.customOperations.length > 0) {
        customOperationCodes = this.customOperations.map(item => item.operate);
      }
      return this.operations
        .filter(operation =>
          [
            'new',
            'delete',
            'export',
            'import',
            'activate',
            'deactivate'
          ].includes(operation)
        )
        .concat(
          this.operations.filter(operation =>
            customOperationCodes.includes(operation)
          )
        );
    },
    buttonsOfButtonGroup() {
      const that = this;
      const buttons = this.normalOperations.filter(
        item => this.operationsButtons.includes(item.operate) && !item.type
      );
      return JSON.parse(JSON.stringify(buttons)).map((item, index) => {
        // console.log(item);
        if (index === 0) {
          item.isPrimary = true;
        }
        item.method = item.operate;
        item.operate = () => {
          that.operateData(item.method);
        };
        return item;
      });
    },
    buttonsMore() {
      const that = this;
      const buttons = this.normalOperations.filter(
        item => this.operationsButtons.includes(item.operate) && item.type
      );
      return JSON.parse(JSON.stringify(buttons)).map((item, index) => {
        if (index === 0) {
          item.isPrimary = true;
        }
        item.method = item.operate;
        item.operate = () => {
          that.operateData(item.method);
        };
        return item;
      });
    },
    selectedIds() {
      return this.selectedDatas.map(data => data[this.tableName + 'id']);
    },
    orderBy() {
      return this.orderByList.map(orderBy => orderBy.value).join();
    }
  },
  watch: {
    operationsButtons() {
      if (this.operationsButtons.length > 0 && this.operations.length > 0) {
        const vm = this;
        this.operationsButtons.sort(
          (obj1, obj2) =>
            vm.operations.indexOf(obj1) - vm.operations.indexOf(obj2)
        );
      }
    },
    operations() {
      this.buttonSort();
    },
    searchParam(val) {
      this.searchList = val;
    }
  },
  created() {
    if (this.titleList.key) {
      this.initTitleSelect();
    }
  },
  methods: {
    initTitleSelect() {
      if (
        undefined != this.titleList.selected &&
        null != this.titleList.selected
      ) {
        this.selected = this.titleList.selected;
      }
      this.titleSelectChange(this.selected);
    },
    titleSelect(val) {
      this.selected = val;
      this.titleSelectChange(val, true);
      // this.$emit('input', val);
    },

    //标题下拉查询
    titleSelectChange(val, flag) {
      let searchObj = this.titleList.value[val];
      let key = this.titleList.key;
      if (!rt.isNilOrEmptyArray(this.searchList)) {
        let index = this.searchList.findIndex(list => list.key == key);
        if (
          index >= 0 &&
          (searchObj.value == -1 ||
            null == searchObj.value ||
            undefined == searchObj.value)
        ) {
          this.searchList.splice(index, 1);
        } else {
          this.searchList.splice(index, 1, {
            key: key,
            value: searchObj.value
          });
        }
      } else {
        if (
          null != searchObj.value &&
          undefined != searchObj.value &&
          -1 != searchObj.value
        ) {
          this.searchList = [{ key: key, value: searchObj.value }];
        }
      }
      if (flag) {
        this.refreshTable();
      }
    },

    //获取数据及分页
    tableFetch(page) {
      let dataApi = `api/${this.controllerName}/search`;
      let quickSearchList = [];
      if (this.inputSearchParam.length > 0) {
        this.inputSearchParam.forEach(key => {
          if (
            !rt.isNil(this.quickSearchValue) &&
            !rt.isNullOrWhiteSpace(this.quickSearchValue)
          ) {
            quickSearchList.push({ key: key, value: this.quickSearchValue });
          }
        });
      }
      let param = {
        pageIndex: page.pageIndex,
        pageSize: page.pageSize
      };
      if (!rt.isNilOrEmptyArray(quickSearchList)) {
        param.quickSearch = quickSearchList;
      }
      if (!rt.isNilOrEmptyArray(this.searchList)) {
        param.searchList = this.searchList;
      } else {
        param.searchList = [];
      }
      if (!rt.isNilOrEmptyArray(this.defaultParam)) {
        param.searchList = param.searchList.concat(this.defaultParam);
      }
      if (!rt.isNilOrEmptyArray(this.orderByList)) {
        param.orderBy = this.orderByList;
      }

      if (
        !rt.isNil(this.customLoadDataApi) &&
        this.customLoadDataApi.constructor === String &&
        !rt.isNilOrWhiteSpace(this.customLoadDataApi)
      ) {
        dataApi = this.customLoadDataApi;
      }
      return new Promise(resolve => {
        rt.post(dataApi, param)
          .then(res => {
            this.tableTotals = res.count;
            resolve(res.list);
          })
          .catch(error => {
            rt.showErrorToast(error);
          });
      }).then(res => {
        return res;
      });
    },
    resetTableParam() {
      if (this.reset && typeof this.reset === 'function') {
        this.searchList = [];
        this.reset();
        this.$refs['multipleTable'].fetchData();
      }
    },
    async refreshTable() {
      this.$refs['multipleTable'].handleIndexChange(1);
    },
    searchBtn() {},
    //复选框的值
    handleSelectionChange(val) {
      this.selectedDatas = val;
    },
    operateData(operation) {
      const customOperation = this.customButtonOperation[operation];
      if (typeof customOperation === 'function') {
        customOperation(this.selectedIds, this.selectedDatas);
        return;
      }
      if (operation === 'new') {
        this.gotoEditPage();
        return;
      }
      if (operation === 'export') {
        if (this.isShowExportDialog) {
          this.exportForm.visible = true;
        } else {
          this.exportViewData();
        }
        return;
      }
      const { operate, method } = util.operations[operation];
      if (rt.isNilOrEmptyArray(this.selectedIds)) {
        rt.showErrorToast(`请至少选择一项进行${operate}操作`);
        return;
      }
      const confirmMessage = `您一共选择了${this.selectedIds.length}条记录，确认要${operate}这些记录？`;
      rt.confirm(confirmMessage, { type: 'warning' })
        .then(() => {
          rt.post(`api/${this.controllerName}/${method}`, this.selectedIds)
            .then(() => {
              rt.showSuccessToast(`${operate}成功`);
              this.refreshTable();
            })
            .catch(error => {
              rt.showErrorToast(error.message);
            });
        })
        .catch(() => {});
    },
    buttonSort() {
      if (this.operations.length > 0) {
        const vm = this;
        this.normalOperations.sort(
          (obj1, obj2) =>
            vm.operations.indexOf(obj1.operate) -
            vm.operations.indexOf(obj2.operate)
        );
      }
    },
    handleClick(operate) {
      if (
        operate &&
        Object.prototype.toString.call(operate) === '[object Function]'
      ) {
        operate();
      }
    },
    handleRowLinkClick(row) {
      if (this.filterMuti(row)) {
        return;
      }
      this.gotoPage(row);
    },
    gotoPage(row) {
      // 清空选中项
      // this.$refs['multipleTable'].clearSelection();
      this.selectedDatas = [];
      let linkPageType = this.linkPageType;
      if (
        this.handleLinkPageType &&
        typeof this.handleLinkPageType === 'function'
      ) {
        linkPageType = this.handleLinkPageType(row);
      }
      switch (linkPageType) {
        case 'edit':
          this.gotoEditPage(row);
          break;
        case 'readonly':
          this.gotoReadonlyPage(row);
          break;
        default:
          break;
      }
    },
    gotoEditPage(row) {
      let fileName = util.replaceSolidus(this.controllerName);
      switch (this.linkPageMode) {
        case 'replace':
          {
            let routeParams = {};
            if (row) {
              routeParams = this.setParams
                ? this.setParams(row)
                : {
                    id: row[`${this.tableName}id`],
                    relatedAttr: this.relatedAttr
                  };
            } else {
              routeParams = this.setParams
                ? this.setParams(row)
                : { relatedAttr: this.relatedAttr };
            }
            const route = { name: `${fileName}edit`, params: routeParams };
            this.$router.push(route);
          }
          break;

        default:
          break;
      }
    },
    gotoReadonlyPage(row) {},
    async handleHeaderClick(column) {
      this.lastClickedColumn = column.property;
    },
    async handleSortChange(obj) {
      await this.$nextTick();
      const currentProp = obj.prop || this.lastClickedColumn;
      this.orderByList =
        obj.order === null
          ? []
          : [
              {
                prop: currentProp,
                value: `${obj.order.replace('ending', '')}`
              }
            ];
      this.$refs['multipleTable'].fetchData();
    },
    selectable(row, index) {
      let flag = false;
      if (!rt.isNil(this.disableMulti.column)) {
        let keys = Object.keys(this.disableMulti.column);
        let values = Object.values(this.disableMulti.column);
        flag = values[0].includes(row[keys[0]]);
      }
      return !flag;
    },
    filterMuti(row) {
      return !this.selectable(row);
    },
    customAction(row, actionId) {
      if (this.filterMuti(row)) {
        return;
      }
      this.customizeAction(row, actionId);
    }
  }
};
</script>
